问题引入

dva一般用connect进行model数据与组件绑定。通过例子来看具体的绑定方式。具体的流程如下:

  1. 组件里面有一个按钮,点击按钮进入model层的effect方法
  2. model中的effect执行完毕后,调用reducer刷新model中state值,同时也刷新组件的显示效果

在这个结构里,有一个问题就是组件中显示的值为model中的state,那么这就需要将组件中的数据与model中的state作绑定。

现在有一个组件:

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
interface MyProps{
dispatch:Dispatch
num:number
}
interface MyState {
num:number
iconLoading:boolean
}
class OtherComponent extends Component<MyProps, MyState> {
state = {
num:12,
iconLoading:false
};
enterIconLoading = () => {
const {dispatch}=this.props;
this.setState({ iconLoading: true });
const {num} = this.props
dispatch({
type: "otherModel/fetchNum",// 这里就会触发models层里面effects中fetchNum方法(也可以直接触发reducer中方法,看具体情况) ,test就是models里的命名空间名字
payload2: {
numCount:num,
}
})
this.setState({iconLoading:false})
};
render() {
const {num} = this.props
return (
<div>
<Button type="primary"
icon="poweroff"
loading={this.state.iconLoading}
onClick={this.enterIconLoading}>
{num}
</Button>
</div>
)
}
}
export default OtherComponent;

model层中代码:

jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
export interface StateType {
num: number
iconLoading: boolean
}

export interface ModelType {
namespace: string;
state: StateType;
effects: {};
reducers: {};
}
const Model: ModelType = {
namespace: 'otherModel',
state: {num: 1873, iconLoading: false},
reducers: {
addNum(state: StateType, {payload: {num}}:{payload:{num:number}}) {
return {...state, num}
}
},
effects: {
* fetchNum({payload2}: { payload2: AnyAction }, {call,put }: EffectsCommandMap & { select: <T>(func: (state: StateType) => T) => T }) {//fetchNum方法名,payload2是传来的参数,是个对象,如果没参数可以写成{_,{call,put,select}}
// const {data} = yield call(myService.doit, {anum: payload2.numCount}) // myService是引入service层那个js的一个名字,anum是后台要求传的参数,data就是后台返回来的数据
//const m = yield select((state) => state.test.num) //select就是用来选择上面state里的,这里没用上
console.log(payload2)
yield put({
type: "addNum",// 这就是reducer中addNum方法, put就是用来触发上面reducer的方法,payload里就是传过去的参数。 同时它也能触发同等级effects中其他方法。
payload: {
num: payload2.numCount + 1, // 把后台返回的数据赋值给了num,假如那个reducer中方法是由这里effects去触发的,那个num名必须是这里名字num,如果reducer中方法不是这触发,那名字可随便起
},
})
}
},


}

export default Model;

现在可以看到两边的逻辑都已经写好了,看看如何绑定model中的num值。

方法一

传统方式,使用connect,在组件中写入。这样写之后,就会在组件的props中生成一个otherModel的属性。
使用的时候用const {otherModel}=this.props即可取到。这里的otherModel为model 的命名空间。

jsx
1
2
3
4
5
6
7
function mapStateToProps (model) {
const { otherModel} = model
return {
otherModel,// 在这return,上面才能获取到
}
}
export default connect(mapStateToProps)(OtherComponent);

如果想使用model state中的某几个属性,那么使用,如下:

jsx
1
2
3
4
5
6
function mapStateToProps (model) {
const { num} = model.otherModel
return {
num,// 在这return,上面才能获取到
}
}

方法二

现在一般都用@connect装饰器的模式。这种模式看起来更简单一些,但是初次使用,语法上还是需要看一下的:

jsx
1
@connect(({otherModel}:{otherModel:StateType})=>({otherModel}))

在这里需要注意,这样引入的话,类似于上面的全部引入。但是如果想要部分引入属性。需要用下面的方法:

jsx
1
@connect(({otherModel}:{otherModel:StateType})=>({num:otherModel.num}))

即传入的参数永远为otherModel,也就是这个唯一的命名空间